

public class Des {
	private static final int[] PC_1 = {
        57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51,
        43, 35, 27, 19, 11, 3, 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7,
        62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20,
        12, 4
    }; // 56
	
	private static final int[] PC_2 = {
        14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16,
        7, 27, 20, 13, 2, 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44,
        49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
    }; // 48
	
	private static final int[]leftMove={
		1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1
	};//16
	
	 private static final int[] IP = {
         58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54,
         46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33,
         25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21,
         13, 5, 63, 55, 47, 39, 31, 23, 15, 7
     }; // 64

	 private static final int[] IP_1 = {
         40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6,
         46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12,
         52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18,
         58, 26, 33, 1, 41, 9, 49, 17, 57, 25
     }; // 64
	 
	 private static final int[] E = {
         32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13,
         14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24,
         25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1
     }; // 48
	 
	 private static final int[][][] S_Box = {
         {
             { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 },
             { 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8 },
             { 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0 },
             { 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 }
         },
         { // S_Box[1]
             { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 },
             { 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 },
             { 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15 },
             { 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 }
         },
         { // S_Box[2]
             { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 },
             { 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1 },
             { 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7 },
             { 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 }
         },
         { // S_Box[3]
             { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 },
             { 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 },
             { 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4 },
             { 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 }
         },
         { // S_Box[4]
             { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 },
             { 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6 },
             { 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14 },
             { 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 }
         },
         { // S_Box[5]
             { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 },
             { 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8 },
             { 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6 },
             { 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 }
         },
         { // S_Box[6]
             { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 },
             { 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6 },
             { 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2 },
             { 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 }
         },
         { // S_Box[7]
             { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 },
             { 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2 },
             { 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8 },
             { 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 }
         } // S_Box[8]
     };

	 
	 private static final int[] P = {
         16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8,
         24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
     }; // 32
	 
	//16组48位子秘钥生成,注意输入输出应该为二进制数
	private static void SubKeyIntalize( int[]key,int [][]subKey){
		int i,j;
		int[] K0=new int [56];
		for ( i=0;i<56;i++)
			K0[i]=key[PC_1[i]-1];
		for( i=0;i<16;i++){
			LeftMove(K0,leftMove[i]);
			for(j=0;j<48;j++){
				subKey[i][j]=K0[PC_2[j]-1];
			}
		}
	}
	
	// 循环移位操作函数
	private static void LeftMove (int[]k,int b){
		int i;
		int[] c0 = new int[28];
		int[] d0 = new int[28];
		int[] c1 = new int[28];
		int[] d1 = new int[28];
		for (i = 0; i < 28; i++) {
			c0[i] = k[i];
			d0[i] = k[i + 28];
		}
		if (b == 1) {
			for (i = 0; i < 27; i++) { // 循环左移一位
				c1[i] = c0[i + 1];
				d1[i] = d0[i + 1];
			}
			c1[27] = c0[0];
			d1[27] = d0[0];
		} else if (b == 2) {
			for (i = 0; i < 26; i++) { // 循环左移两位
				c1[i] = c0[i + 2];
				d1[i] = d0[i + 2];
			}
			c1[26] = c0[0];
			d1[26] = d0[0];
			c1[27] = c0[1];
			d1[27] = d0[1];
		}
		for (i = 0; i < 28; i++) {
			k[i] = c1[i];
			k[i + 28] = d1[i];
		}
	}
	    
	//将字节数组转换为二进制数存储
	private int[] ByteToBirnary(byte[] b) {
        int i;
        int j;
        int t=b.length;
        //if((b.length%8)!=0)throw new RuntimeException("数据出错！");
        //将整数转换成补码
        int[] bu = new int[t];
        for (i = 0; i < t; i++) {
            bu[i] = b[i];
            if (bu[i] < 0) {
                bu[i] += 256;
                bu[i] %= 256;
            }
        }
        //风别将每个字节转换成二进制数字存储在数组中
        int[] IntBinary = new int[8*t];
        for (i = 0; i < t; i++) {
            for (j = 0; j < 8; j++) {
            	IntBinary[((i * 8) + 7) - j] = bu[i] % 2;
                bu[i] = bu[i] / 2;
            }
        }
        return IntBinary;
    }
	
	//二进制转换成字节数组
	private byte[] BirnaryToByte(int[]arr){
		int t=arr.length/8;//一共t个字节
		if((arr.length%8)!=0)
			throw new RuntimeException("数据出错！");
		byte[]st=new byte[t];
		
		//计算每个字节
		for(int i=0;i<t;i++)
			for(int j=0;j<8;j++){
				st[i]+=(arr[(i<<3)+j]<<(7-j));
			}
		//求机器码真值
		for (int i=0; i < t; i++) {
            st[i] %= 256;
            if (st[i] > 128)//负数
                st[i] -= 255;
		} 
		return st;
	}
	
	//输入数据，如果flag为1，加密；为0否则解密
	private int[] DesEncrypt (int[]data,int[][]subKey,int flag){
		int i,j,t,m,n,h;
		m=data.length;
		if((m%64)!=0)
			throw new RuntimeException("数据出错！");
		int[]desData=new int[m];//存储加解密后的数据
		int[] groupData=new int[64];//存储每个原始分组数据
		int[] groupDesData=new int[64];//存储每个加解密后的分组数据
		int[] L0=new int[32];
		int[] R0=new int[32];
		int[] temp=new int[32];
		int[] EX=new int[48];
		int[][] S=new int[8][6];
		int[] boxData=new int[8];
		int[] boxValue=new int[32];
		
		for(n=0;n<m/64;n++){
			//一共进行i个分组加解密
			for(h=0;h<64;h++){
				groupData[h]=data[n*64+h];//得到每个分组
			}
			//加密开始
			//初始IP置换
			for(i=0;i<32;i++){
				L0[i]=groupData[IP[i]-1];
				R0[i]=groupData[IP[i+32]-1];
			}
			
			//16轮迭代
			for(i=0;i<16;i++){
				temp=R0;
				
				//扩展运算、模二加密
				for(j=0;j<48;j++){
					EX[j]=R0[E[j]-1];
					if(flag==1)EX[j]=EX[j]^subKey[i][j];
					else EX[j]=EX[j]^subKey[15-i][j];//加密与解密子秘钥异或顺序相反
				}
				
				//压缩变换
				for(t=0;t<8;t++){
					//分为8个盒
					for(j=0;j<6;j++){
						S[t][j]=EX[t*6+j];
					}
					//每个盒找出对应的十进制数
					boxData[t]=S_Box[t][(S[t][0] << 1) + S[t][5]][(S[t][1] << 3)
							+ (S[t][2] << 2) + (S[t][3] << 1) + S[t][4]];
					
					//将十进制变换输出4位二进制数
					for (j = 0; j < 4; j++) {
						boxValue[((t * 4) + 3) - j] = boxData[t] % 2;
						boxData[t] = boxData[t] / 2;
					}
				}
				
				//P盒置换、生成下一个
				for(j=0;j<32;j++){
					R0[j]=boxValue[P[j]-1]^L0[j];
				}
				L0=temp;
				}
			//IP逆置换
			for(i=0;i<32;i++){
				groupDesData[i]=L0[i];
				groupDesData[i+32]=R0[i];
			}
			for(i=0;i<64;i++){
				desData[n*64+i]=groupDesData[IP_1[i]-1];
			}
		}
		return desData;
	}
	
	public byte[] DesTest(byte[] key,byte[] data,int flag){
		int gp=data.length/8;//分组加密的个数
		if(key.length!=8||(data.length%8)!=0||(flag!=1&&flag!=0)){
			throw new RuntimeException("输入格式有误！");
		}
		int[]binaryKey=new int[64];//字节秘钥转换为二进制
		int [][]subKey=new int [16][48];//存储16条子秘钥
		int[]binaryData=new int[64*gp];//存储原始的二进制数据
		int[]binaryDesData=new int[64*gp];//存储加密或解密过的二进制数据
		byte[]byteDesData=new byte[8*gp];//存储加密或解密过的byte数据
		
		binaryKey=ByteToBirnary(key);
		SubKeyIntalize(binaryKey, subKey);//生成16条子秘钥
		
		
		binaryData=ByteToBirnary(data);
		binaryDesData=DesEncrypt(binaryData,subKey,flag);
		byteDesData=BirnaryToByte(binaryDesData);
		return byteDesData;
	}
	
	//测试主函数
	public static void main(String[]args){
		byte[] key1={'k','q',0,1,6,4,9,5};
		byte[] key2={'k','h',0,1,6,4,9,5};
		byte[] data={'s','a',1,5,2,2,6,4,8,6,'k','e','q','i','n','.'};
		//byte[] data2={'g','a',1,5,2,2,6,4,8,6,'k','e','q','i','n','.'};
		byte[]  desData1,desData2;
		int flag=1;
		Des des=new Des();
		desData1= des.DesTest(key1,data,flag);
		desData2=des.DesTest(key2,data,flag);
		System.out.println("秘钥1：");
		for(int i=0;i<key1.length;i++){
			System.out.print(key1[i]+" ");
		}
		System.out.println();
		System.out.println("秘钥2：");
		for(int i=0;i<key2.length;i++){
			System.out.print(key2[i]+" ");
		}
		System.out.println();
		
		System.out.println("加密密文1：");
		for(int i=0;i<desData1.length;i++){
			System.out.print(desData1[i]+" ");
		}
		System.out.println();
		
		System.out.println("加密密文2：");
		for(int i=0;i<desData2.length;i++){
			System.out.print(desData2[i]+" ");
		}
		System.out.println();
		
	}
}
